//{==================================================================================================
//! @file MatrixTranspose.cpp
//! @date 2013-09-28
//! @mainpage Program for (N,N) matrix transpose
//! @author Kirill Shcherbatov <kshcherbatov@gmail.com>, 376 group, DCAM MIPT
//! @version 1.0
//! @note Task A, varriant 2, test 2007, MIPT
//}===================================================================================================

//****************************************************************************************************
#include <stdio.h>
#include <stdlib.h>
//****************************************************************************************************

//****************************************************************************************************
#define _EJC
#define PARANOID_MODE
//****************************************************************************************************

//****************************************************************************************************
//! @def   OUT
//! @note  -Use OUT to print your text in console. It is checking _EJC declaration.
//! @note  -Only if _EJC is defined then the program prints your text.
//! @note  --You also can define _EJC in compilation command (g++ main.cpp -D _EJC)
//----------------------------------------------------------------------------------------------------
#ifdef _EJC
    #define OUT printf
#else
    #define OUT if (0) printf
#endif // _EJC
//****************************************************************************************************


//****************************************************************************************************
//! @def    VALID
//! @param  CONDITIONAL for checking
//! @param  MESSAGE for displaying if CONDITIONAL is false
//! @note   -It checks the validity of the expression.
//! @note   -Program will use OUT to display MESSAGE
//! @note   -If sended conditional is false, program will be terminated sending 1 message
//----------------------------------------------------------------------------------------------------
#ifdef  PARANOID_MODE
    #define VALID( CONDITIONAL, MESSAGE )       \
    if (!(CONDITIONAL))                         \
    {                                           \
        OUT  ( MESSAGE );                       \
        exit ( 1 );                             \
    } // VALID in PARANOID_MODE
#else
    #define VALID( CONDITIONAL, MESSAGE ) \
    (void) CONDITIONAL;
#endif
//****************************************************************************************************

//****************************************************************************************************
//! @def    CHECK
//! @param  CONDITIONAL for checking
//! @param  MESSAGE for displaying if CONDITIONAL is false
//! @note   -It checks the validity of the expression.
//! @note   -Program will use OUT to display MESSAGE
//! @note   -If sended conditional is false, program will be terminated sending 1 message
//! @warning   IN RELIASE MODE IT WILL BE REMOOVED
//----------------------------------------------------------------------------------------------------
#ifdef PARANOID_MODE
    #define CHECK( CONDITIONAL, MESSAGE )       \
    if (!(CONDITIONAL))                         \
    {                                           \
        OUT  ( MESSAGE );                       \
        exit ( 1 );                            \
    } // CHECK in PARANOID_MODE
#else
    #define CHECK( CONDITIONAL, MESSAGE )
#endif
//****************************************************************************************************

//****************************************************************************************************
int transpose ( long long unsigned int * matrix, char matrix_size );
//****************************************************************************************************

//****************************************************************************************************
//! @param - number of sending arguments
//! @param argv[] - arguments, include generated by OS
//! @return 0 on success
//----------------------------------------------------------------------------------------------------
int main(int, const char* argv[])
{
    OUT ( "%s (%s) %s %s:\n\n", argv[ 0 ], __FILE__, __DATE__, __TIME__ );
    OUT ( "#Programm for (N,N) matrix transponation.\n\n" );

    const char SUPRENUM = 50;

    OUT ( "#Enter size of you (N,N) matrix. It should be natural integer from (0; %d)\n"
          "#N = ", SUPRENUM);
    char mtxSize = 0;

    VALID ( scanf("%d",&mtxSize) == 1 , "#Problems with inputed N. Read the instructions above & try again.\n" );

    CHECK ( mtxSize > 0 ,  "#Inputed N is incorrect. N should be greater than 0.\n" );
    CHECK ( mtxSize < SUPRENUM , "#Inputed N is incorrect. N should be lower than SUPRENUM.\n");

    long long unsigned int * matrix = (long long unsigned int *)calloc (mtxSize * mtxSize, sizeof (long long unsigned int) );

    VALID ( matrix != NULL , "#Sorry, but there is not enough memory for you matrix...\n" );

    OUT("#Enter you %d matrix values\n", mtxSize * mtxSize);

    const long long unsigned int precalc = 1llu << 31;

    for ( register char i=0; i < mtxSize; i++ )
        for ( register char j=0; j < mtxSize; j++ )
        {
            VALID ( scanf ( "%lld", &matrix[i*mtxSize + j] ) == 1, "#Problems with inputed N. Read the instructions above & try again.\n" );
            CHECK ( abs ( mtxSize ) < precalc ,  "#Inputed value is incorrect. It should be from [-2^31; 2^31].\n" );
        }
    if (transpose (matrix, mtxSize) != 0)
    {
        OUT ("#Sorry, it looks like bug in a programm code in function transpose, please report the developer..\n");
        free ( matrix );
        exit (1);
    }
    OUT("\n"
        "#Ok, resulting transposed matrix is \n\n");

    for ( register char i=0; i < mtxSize; i++ )
    {
        for ( register char j=0; j < mtxSize; j++ )
            printf ( "%lld ", matrix[i*mtxSize + j] );
        printf ("\n");
    }

    free ( matrix );
    matrix = NULL;

    return 0;
}
//****************************************************************************************************

//****************************************************************************************************
//! @param matrix to transpose
//! @param matrix_size size of matrix
//! @return 0 on succes
//! @note transpose sending matrix
//----------------------------------------------------------------------------------------------------
int transpose (long long unsigned int * matrix, char matrix_size)
{
    register char i=0, k=1;

    while ( i < matrix_size * matrix_size )
    {
        char t=1;

        for ( register char j = i + 1; j < matrix_size * k; j++ )
        {
            long long unsigned int temp = matrix[j];
            #define Y( CONDITIONAL ) \
                CONDITIONAL+t*(matrix_size - 1)
            matrix[j] = matrix[ Y (j) ];
            matrix[ Y (j) ] = temp;
            #undef Y ( X )
            t++;
        }

        i = (matrix_size + 1) * k++;
    }

    return 0;
}
//****************************************************************************************************
